home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 4 / Amiga Tools 4.iso / tools / protect-your-privacy / p.g.p. / pgpsendmail / source / pgpsendmail.c < prev    next >
C/C++ Source or Header  |  1996-02-26  |  17KB  |  485 lines

  1. /*
  2.  *      $Filename: pgpsendmail.c $
  3.  *      $Revision: 1.45 $
  4.  *      $Date: 1994/03/21 14:54:52 $
  5.  *
  6.  *      Copyright (C) 1993 by Peter Simons <simons@peti.GUN.de>
  7.  *
  8.  *      This program is free software; you can redistribute it and/or
  9.  *      modify it under the terms of the GNU General Public License as
  10.  *      published by the Free Software Foundation; either version 2 of
  11.  *      the License, or (at your option) any later version.
  12.  *
  13.  *      This program is distributed in the hope that it will be useful,
  14.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  *      General Public License for more details.
  17.  *
  18.  *      You should have received a copy of the GNU General Public License
  19.  *      along with this program; if not, write to the Free Software
  20.  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  *      $Id: pgpsendmail.c,v 1.45 1994/03/21 14:54:52 simons Exp simons $
  23.  *
  24.  */
  25.  
  26.  
  27. /**************************************************************************
  28.  *                                                                        *
  29.  * Section: Macros, Definitions, Includes, Structures                     *
  30.  *                                                                        *
  31.  **************************************************************************/
  32.  
  33. /************************************* Includes ***********/
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <fcntl.h>
  37. #include <string.h>
  38. #include <ctype.h>
  39.  
  40. #include <exec/execbase.h>
  41.  
  42. #include "pgpsendmail.h"                /* standard defines */
  43. #include "protos.h"                     /* protoypes of all available routines */
  44.  
  45. #include "pgpsendmail_rev.h"            /* bumprevision stuff (AmigaOS only) */
  46.  
  47. /************************************* Prototypes *********/
  48. void my_exit(void);
  49. void sendmail(void);
  50.  
  51. /************************************* Defines ************/
  52. #define PGP             "PGP -fesa <%s >%s %s +batchmode"
  53. #define PGPKEYLIST      "UULib:PGPKeys.lst"
  54.  
  55. #define BODY_ID         "Automatically encrypted message-body follows:\n\n"
  56.  
  57. /************************************* global Variables ***/
  58. static const char __OSVer[] = VERSTAG;
  59. static const char __RCSId[] = "$Id: pgpsendmail.c,v 1.45 1994/03/21 14:54:52 simons Exp simons $";
  60. char PRGNAME[] = "PGPSendmail";
  61.  
  62. struct NetSupportLibrary *NetSupportBase;
  63. FILE *mailfh, *tmpfh;
  64. char mailfilename[L_tmpnam], tmpfilename[L_tmpnam], encryptedfilename[L_tmpnam], *argline, *tmpbuf;
  65. int exitPipe = 1;
  66.  
  67. /**************************************************************************
  68.  *                                                                        *
  69.  * Section: main program                                                  *
  70.  *                                                                        *
  71.  **************************************************************************/
  72.  
  73. int main(int argc, char **argv)
  74. {
  75.         extern struct ExecBase *SysBase;
  76.         BPTR pipe, tmp_pipe;
  77.         char **receipients, *cmdbuf, *header, *tmp, *ptr;
  78.         int rc;
  79.  
  80.  
  81.         /*
  82.          * Initialize the requires resources and return if something fails!
  83.          */
  84.  
  85.         if (SysBase->LibNode.lib_Version < 37) {
  86.                 fprintf(stderr, "%s: Kickstart 2.04 or later is required!", PRGNAME);
  87.                 return 20;
  88.         }
  89.         if (atexit(my_exit)) {
  90.                 fprintf(stderr, "%s: Could not install my exit handler!\n", PRGNAME);
  91.                 return 20;
  92.         }
  93.         if (!(NetSupportBase = (struct NetSupportLibrary *) OpenLibrary("netsupport.library", 0L))) {
  94.                 fprintf(stderr, "%s: Failed opening NetSupport.Library!", PRGNAME);
  95.                 return 20;
  96.         }
  97.         if (!(cmdbuf = malloc(MAX_CMDLINELEN)) || (!(tmpbuf = malloc(MY_BUFLEN)))) {
  98.                 MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Failed allocating my buffers!");
  99.                 return 20;
  100.         }
  101.         tmpnam(mailfilename);
  102.         tmpnam(tmpfilename);
  103.         tmpnam(encryptedfilename);
  104.         argline = GetOriginalCmdLine(argc, argv);       /* Re-build the original commandline, because
  105.                                                          * the real sendmail will need it later.
  106.                                                          */
  107.  
  108.         /*
  109.          * Copy standard input to a temporary file for security reasons.
  110.          */
  111.  
  112.         if (!(mailfh = fopen(mailfilename, "w"))) {
  113.                 MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Failed opening %s!", mailfilename);
  114.                 return 20;
  115.         }
  116.         while (fgets(tmpbuf, MY_BUFLEN, stdin)) {
  117.                 if (fputs(tmpbuf, mailfh) == EOF) {
  118.                         MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Can't write to %s!", mailfilename);
  119.                         return 20;
  120.                 }
  121.         }
  122.         fclose(mailfh); mailfh = NULL;
  123.         MakeLogEntry(PRGNAME, MLE_DEBUG2, "original mail is now in '%s'.", mailfilename);
  124.  
  125.  
  126.         /*
  127.          * Now that the mail is safe, install an exit handler that pipes the
  128.          * file to sendmail when we exit, to make sure the mail will not be
  129.          * lost under error condition.
  130.          */
  131.  
  132.         if (atexit(sendmail)) {
  133.                 fprintf(stderr, "%s: Could not install my exit handler!\n", PRGNAME);
  134.                 return 20;
  135.         }
  136.  
  137.  
  138.  
  139.         /*
  140.          * Load the mail header for RFC routines.
  141.          */
  142.  
  143.         if (!(header = malloc(10*1024))) {      /* allocate 10k for the mail header */
  144.                 MakeLogEntry(PRGNAME, MLE_ERROR, "Failed allocating my buffers!");
  145.                 return 10;
  146.         }
  147.         if (!(mailfh = fopen(mailfilename, "r"))) {
  148.                 MakeLogEntry(PRGNAME, MLE_ERROR, "Failed opening %s!", mailfilename);
  149.                 return 10;
  150.         }
  151.         tmp = header;
  152.         while (fgets(tmp, MY_BUFLEN, mailfh)) {
  153.                 if (strlen(tmp) == 1)           /* Have we reached the mail body? */
  154.                         break;
  155.                 tmp += strlen(tmp);
  156.         }
  157.  
  158.  
  159.  
  160.         /*
  161.          * Determine receipients to decide whom to encrypt to.
  162.          */
  163.  
  164.         receipients = FindReceipients(header);
  165.         free(header);                                   /* Header isn't needed anymore. */
  166.  
  167.         if (!receipients || (!*receipients)) {
  168.                 MakeLogEntry(PRGNAME, MLE_ERROR, "Can't determine receipient of message.");
  169.                 return 10;
  170.         }
  171.         else
  172.                 MakeLogEntry(PRGNAME, MLE_DEBUG2, "receipients (including aliases): %s", ArrayToLine(receipients));
  173.         receipients = ExpandAliases(receipients);
  174.         if (!receipients || (!*receipients)) {
  175.                 MakeLogEntry(PRGNAME, MLE_ERROR, "Can't determine receipient of message.");
  176.                 return 10;
  177.         }
  178.         else
  179.                 MakeLogEntry(PRGNAME, MLE_DEBUG2, "receipients (aliases expanded): %s", ArrayToLine(receipients));
  180.         MakeDomainAddress(receipients);
  181.  
  182.  
  183.  
  184.         /*
  185.          * Check wether all keys are available or not.
  186.          */
  187.  
  188.         if ((CheckKeyAvailability(receipients)) == 0) {
  189.                 MakeLogEntry(PRGNAME, MLE_DEBUG2, "Not all receipients have a valid public key.");
  190.                 return 0;
  191.         }
  192.  
  193.  
  194.  
  195.         /*
  196.          * Ask user wether this mail should be encrypted or not.
  197.          */
  198.  
  199.         ptr = GetConfig(NULL, CONFIRMENCRYPTION, NULL, "y");
  200.         if (ptr[0] == 'y' || ptr[0] == 'Y')
  201.                 if (!ConfirmEncryption()) {
  202.                         MakeLogEntry(PRGNAME, MLE_INFO, "Encryption denied by user.");
  203.                         return 0;
  204.                 }
  205.  
  206.  
  207.         /*
  208.          * Copy messagebody for encryption.
  209.          */
  210.  
  211.         if (!(tmpfh = fopen(tmpfilename, "w"))) {
  212.                 MakeLogEntry(PRGNAME, MLE_ERROR, "Failed opening %s!", tmpfilename);
  213.                 return 5;
  214.         }
  215.         while (fgets(tmpbuf, MY_BUFLEN, mailfh)) {      /* The fileposition is at the begin of the
  216.                                                          * mailbody because we read the header earlier.
  217.                                                          */
  218.                 if (fputs(tmpbuf, tmpfh) == EOF) {
  219.                         MakeLogEntry(PRGNAME, MLE_ERROR, "Can't write to %s!", tmpfilename);
  220.                         return 5;
  221.                 }
  222.         }
  223.         fclose(mailfh); mailfh = NULL;
  224.         fclose(tmpfh); tmpfh = NULL;
  225.  
  226.  
  227.  
  228.         /*
  229.          * Encrypt message body.
  230.          */
  231.  
  232.         sprintf(tmpbuf, "PGP -ftea <%s >%s %s", tmpfilename, encryptedfilename, ArrayToLine(receipients));
  233.         MakeLogEntry(PRGNAME, MLE_DEBUG1, "calling '%s'", tmpbuf);
  234.         if (rc = system(tmpbuf)) {
  235.                 MakeLogEntry(PRGNAME, MLE_ERROR, "PGP returned error code %ld", rc);
  236.                 return 5;
  237.         }
  238.         else
  239.                 MakeLogEntry(PRGNAME, MLE_INFO, "succesfully encrypted the mail for %s", ArrayToLine(receipients));
  240.  
  241.         remove(tmpfilename);            /* isn't required anymore */
  242.  
  243.  
  244.  
  245.         /*
  246.          * Call SendMail to handle the message.
  247.          */
  248.  
  249.         sprintf(tmpbuf, "%s %s", FindConfig(SENDMAIL), argline);
  250.         MakeLogEntry(PRGNAME, MLE_DEBUG1, "Calling '%s'", tmpbuf);
  251.  
  252.         /*
  253.          * PORT NOTE: Sorry, but I need POpen() again. To make this stuff work on
  254.          * another platform, you'll have to re-write it completely.
  255.          */
  256.  
  257.         if (pipe = POpen(tmpbuf, MODE_PIPETO)) {
  258.  
  259.  
  260.                 /* Pipe the mail header to sendmail. */
  261.  
  262.                 if (tmp_pipe = Open(mailfilename, MODE_OLDFILE)) {
  263.                         while (FGets(tmp_pipe, tmpbuf, MY_BUFLEN)) {
  264.                                 FPuts(pipe, tmpbuf);
  265.                                 if (strlen(tmpbuf) == 1)        /* header is copied completely */
  266.                                         break;
  267.                         }
  268.                         Close(tmp_pipe);
  269.  
  270.  
  271.                         /* Pipe the encrypted mail body to sendmail. */
  272.  
  273.                         FPuts(pipe, BODY_ID);
  274.                         if (tmp_pipe = Open(encryptedfilename, MODE_OLDFILE)) {
  275.                                 while (FGets(tmp_pipe, tmpbuf, MY_BUFLEN))
  276.                                         FPuts(pipe, tmpbuf);
  277.                                 Close(tmp_pipe);
  278.                         }
  279.  
  280.                         exitPipe = 0;   /* The mail is sent already, we don't need the sendmail()
  281.                                          * exit handler anymore.
  282.                                          */
  283.                 }
  284.  
  285.                 rc = PClose(pipe);
  286.         }
  287.         else {
  288.                 MakeLogEntry(PRGNAME, MLE_ERROR, "Can't send the encrypted mail!");
  289.                 return 5;
  290.         }
  291.  
  292.         return rc;
  293. }
  294.  
  295.  
  296. /**************************************************************************
  297.  *                                                                        *
  298.  * SECTION: Subroutines                                                   *
  299.  *                                                                        *
  300.  **************************************************************************/
  301.  
  302.  /*
  303.   * This exit handler will free all resources allocated by the program
  304.   * when we exit to make sure nothing is wasted under error condition.
  305.   *
  306.   * PORT NOTE: Contains system-dependant stuff!
  307.   */
  308.  
  309. void my_exit(void)
  310. {
  311.         /* Close all open files and delete them afterwards. */
  312.  
  313.         if (mailfh)
  314.                 fclose(mailfh);
  315.         if (tmpfh)
  316.                 fclose(tmpfh);
  317.  
  318.         remove(mailfilename);
  319.         remove(tmpfilename);
  320.         remove(encryptedfilename);
  321.  
  322.  
  323.         /* Free all locked files and close the netsupport.library. */
  324.  
  325.         if (NetSupportBase) {
  326.                 UnLockFiles();
  327.                 CloseLibrary((struct Library *) NetSupportBase);
  328.         }
  329. }
  330.  
  331.  
  332.  /*
  333.   * Pipe the mailfile to sendmail when we exit.
  334.   *
  335.   * PORT NOTE: Because the AmigaOS doen't know popen(), we have to use
  336.   * the routine from the netsupport.library. For other operating systems
  337.   * it will be necessary to replace the whole routine!
  338.   */
  339.  
  340. void sendmail(void)
  341. {
  342.         BPTR pipe, fh;
  343.         int len;
  344.  
  345.         if (!exitPipe)
  346.                 return;
  347.  
  348.         sprintf(tmpbuf, "%s %s", FindConfig(SENDMAIL), argline);
  349.         MakeLogEntry(PRGNAME, MLE_DEBUG1, "Calling '%s'", tmpbuf);
  350.         if (pipe = POpen(tmpbuf, MODE_PIPETO)) {
  351.  
  352.                 /* If the file holding the mail is still open, close it first
  353.                  * to make sure we can access it.
  354.                  */
  355.  
  356.                 if (mailfh) {
  357.                         fclose(mailfh); mailfh = NULL;
  358.                 }
  359.  
  360.                 /* Pipe the whole file to sendmail. */
  361.  
  362.                 if (fh = Open(mailfilename, MODE_OLDFILE)) {
  363.                         while (len = Read(fh, tmpbuf, MY_BUFLEN-1)) {
  364.                                 if (len == -1L)
  365.                                         break;          /* Read() failed */
  366.                                 if (Write(pipe, tmpbuf, len) == -1L)
  367.                                         break;          /* Write() failed */
  368.                         }
  369.                         Close(fh);
  370.                 }
  371.                 else
  372.                         MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Couldn't open mailfile! Mail is lost!!");
  373.                 PClose(pipe);
  374.         }
  375.         else
  376.                 MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Couldn't open pipe to sendmail! Mail is lost!!");
  377. }
  378.  
  379.  
  380.  
  381. char *ArrayToLine(char *array[])
  382. {
  383.         char *line;
  384.  
  385.         if (!(line = malloc(MY_BUFLEN)))
  386.                 return NULL;
  387.         line[0] = '\0';
  388.  
  389.         while (*array != NULL) {
  390.                 strcat(line, *array);
  391.                 strcat(line, " ");
  392.                 array++;
  393.         }
  394.         return line;
  395. }
  396.  
  397.  
  398. int CheckKeyAvailability(char *receipients[])
  399. {
  400.         FILE *fh;
  401.         char *keylist;
  402.         int filelength;
  403.  
  404.         if (*receipients == NULL)
  405.                 return 0;               /* No receipient found! */
  406.  
  407.         LockFile(PGPKEYLIST);
  408.  
  409.         if ((fh = fopen(PGPKEYLIST, "r")) == NULL) {
  410.                 UnLockFile(PGPKEYLIST);
  411.                 return 0;               /* Couldn't open keylist! */
  412.         }
  413.         fseek(fh, 0L, SEEK_END); filelength = ftell(fh);
  414.                                         /* Determine filelength. */
  415.  
  416.  
  417.         /* Allocate buffer and read keylist. */
  418.  
  419.         if (keylist = malloc(filelength+1)) {
  420.                 lseek(fileno(fh), 0, 0);
  421.                 if ((read(fileno(fh), keylist, filelength)) == -1) {
  422.                         fclose(fh);     /* Couldn't read keylist. */
  423.                         UnLockFile(PGPKEYLIST);
  424.                         free(keylist);
  425.                         return 0;
  426.                 }
  427.                 else {          /* Read went fine. */
  428.                         fclose(fh);
  429.                         UnLockFile(PGPKEYLIST);
  430.                         keylist[filelength] = '\0';
  431.  
  432.                         while (*receipients != NULL) {
  433.                                 if (FindKey(*receipients, keylist) == 0) {
  434.                                         free(keylist);
  435.                                         MakeLogEntry(PRGNAME, MLE_DEBUG1, "No key available for <%s>.", *receipients);
  436.                                         return 0;       /* Key is not in keylist. */
  437.                                 }
  438.                                 receipients++;
  439.                         }
  440.                 }
  441.         }
  442.         free(keylist);
  443.         return 1;                       /* Everything is fine. */
  444. }
  445.  
  446. int FindKey(char *key, char *keylist)
  447. {
  448.         char line[MY_BUFLEN];
  449.         int i;
  450.  
  451.         while (*keylist != '\0') {
  452.  
  453.                 /* Is this a valid key-line? */
  454.  
  455.                 if (!strnicmp(keylist, "pub ", strlen("pub "))
  456.                         || !strnicmp(keylist, "    ", strlen("    ")))
  457.                 {
  458.                         for(i = 0; keylist[i] != '\n'; i++)
  459.                                 line[i] = keylist[i];
  460.                         line[i] = '\0';
  461.                         if (stristr(line, key))
  462.                                 return 1;
  463.                 }
  464.  
  465.  
  466.                 /* Find end of line or end of buffer. */
  467.  
  468.                 while (*keylist != '\n' && *keylist != '\0')
  469.                         keylist++;
  470.                 keylist++;
  471.         }
  472.         return 0;
  473. }
  474.  
  475. char *stristr(char *line, char *key)
  476. {
  477.         int i, cmplen = strlen(key), end = strlen(line)-cmplen;
  478.  
  479.         for (i = 0; i <= end; i++)
  480.                 if (strnicmp(&line[i], key, cmplen) == NULL)
  481.                         return &line[i];
  482.         return NULL;
  483. }
  484.  
  485.